#include "myserialport.h"
#include "../myprofile.h"
#include "net/mytcpsocket.h"
#include "utils/singleton.h"
#include <QSerialPortInfo>
#include <QTimer>
#include <cmath>

MySerialPort::MySerialPort() {
  this->setBaudRate(57600);
  this->setDataBits(Data8);
  this->setStopBits(OneStop);
  this->setParity(NoParity);
  this->setFlowControl(NoFlowControl);

  connect(this, &MySerialPort::readyRead, this, &MySerialPort::readyReadSlot);

  sendTimer = new QTimer;
  appendTimer = new QTimer;
  stepTimer = new QTimer;
  sendTimer->setInterval(311);
  appendTimer->setInterval(11111);
  stepTimer->setInterval(943);
  connect(sendTimer, &QTimer::timeout, this, &MySerialPort::sendTimeoutSlot);
  connect(appendTimer, &QTimer::timeout, this,
          &MySerialPort::appendTimeoutSlot);
  connect(stepTimer, &QTimer::timeout, this, &MySerialPort::stepTimerSlot);
  sendTimer->start();
  appendTimer->start();
  stepTimer->start();
}

QStringList MySerialPort::getPortLists() {
  QStringList retLists;
  for (auto &info : QSerialPortInfo::availablePorts()) {
    retLists.append(info.portName());
  }
  return retLists;
}

void MySerialPort::request_sensor() {
  constexpr size_t BUFFER_SIZE = 9;
  unsigned char buff[BUFFER_SIZE];
  buff[0] = 0xfe;
  buff[1] = 0xfe; // 帧头
  buff[2] = 0x00; // 保留
  buff[3] = 0xff;
  buff[4] = 0xff; // 短地址
  buff[5] = 0x09; // 长度
  buff[8] = 0xff; // 终止
  QByteArray data;
  // 0x02节点所有数据
  buff[6] = 0x02;
  buff[7] = 0x05;
  data.append(reinterpret_cast<char *>(buff), BUFFER_SIZE);
  sendList.push_back(data);
  data.clear();
  // 0x03节点所有数据
  buff[6] = 0x03;
  buff[7] = 0x05;
  data.append(reinterpret_cast<char *>(buff), BUFFER_SIZE);
  sendList.push_back(data);
}

void MySerialPort::request_excute(ExcuteType type, double value1,
                                  double value2) {
  constexpr size_t BUFFER_SIZE = 17;
  unsigned char buff[BUFFER_SIZE];
  buff[0] = 0xfe;
  buff[1] = 0xfe; // 帧头
  buff[2] = 0x00; // 保留
  buff[3] = 0xff;
  buff[4] = 0xff;  // 短地址
  buff[16] = 0xff; // 终止
  switch (type) {
  case ExcuteType::LED: {
    // LED
    {
      buff[5] = 0x11; // 长度
      buff[6] = 0x01; // 节点
      buff[7] = 0x01; // 设备
      int line1 = static_cast<int>(value1);
      int line2 = static_cast<int>(value2);
      buff[8] = 0x01;
      buff[9] = static_cast<unsigned char>((line1 & 0xff00) >> 8);
      buff[10] = 0x02;
      buff[11] = static_cast<unsigned char>(line1 & 0xff);
      buff[12] = 0x03;
      buff[13] = static_cast<unsigned char>((line2 & 0xff00) >> 8);
      buff[14] = 0x04;
      buff[15] = static_cast<unsigned char>(line2 & 0xff);
    }
  } break;
  case ExcuteType::FAN: {
    // 风扇
    {
      buff[5] = 0x0a; // 长度
      buff[6] = 0x07;
      buff[7] = 0x01;
      buff[8] = value1 > 0 ? 0x01 : 0x00;
    }
  } break;
  case ExcuteType::STEP: {
    // 步进电机
    {
      buff[5] = 0x0c; // 长度
      buff[6] = 0x07;
      buff[7] = 0x02;
      //      buff[8] = value1 > 0 ? 0x01 : 0x00; //方向
      //      int st_val = static_cast<int>(value2);
      buff[8] = step_state.is_front ? 0x01 : 0x00;
      int st_val = 0;
      if (value1 > 0) // 确认打开电机
        st_val = 80;
      st_val = (st_val < 0) ? 0 : (st_val > 280 ? 280 : st_val);
      buff[9] = static_cast<unsigned char>((st_val >> 8) & 0xff); //距离高位
      buff[10] = static_cast<unsigned char>(st_val & 0xff);       //距离低位
    }
  } break;
  case ExcuteType::RELAY: {
    // 继电器
    {
      buff[5] = 0x0b; // 长度
      buff[6] = 0x07;
      buff[7] = 0x03;
      buff[8] = value1 > 0 ? 0x01 : 0x02;
      buff[9] = value2 > 0 ? 0x01 : 0x00;
    }
  } break;
  case ExcuteType::STEERING:
  case ExcuteType::TEST_EX:
  case ExcuteType::ALL_EXCUTE:
    break;
  }
  QByteArray data;
  data.append(reinterpret_cast<char *>(buff), BUFFER_SIZE);
  sendList.push_front(data);
}

void MySerialPort::step_on(bool open_step) { step_state.is_on = open_step; }

void MySerialPort::readyReadSlot() { handleData(this->readAll()); }

void MySerialPort::sendTimeoutSlot() {
  if (!this->isOpen() || sendList.isEmpty())
    return;
  auto data = sendList.front();
  sendList.pop_front();
  this->write(data);
}

void MySerialPort::appendTimeoutSlot() {
  if (!this->isOpen())
    return;
  MYPROFILE(ProfileType::TRACE, QString("*****请求传感器数据*****"));
  request_sensor();
}

void MySerialPort::stepTimerSlot() {
  if (!this->isOpen())
    return;
  if (step_state.is_on) {
    request_excute(ExcuteType::STEP, 1.0);
  }
}

void MySerialPort::handleData(const QByteArray &data) {
  temp.append(data);
  // split a frame
  if (temp.length() < 9)
    return;
  for (int i = 1; i < temp.length(); i++) {
    if (static_cast<unsigned char>(temp.at(i - 1)) == 0xef &&
        static_cast<unsigned char>(temp.at(i)) == 0xef) {
      temp = temp.mid(i - 1, temp.length());
      if (temp.length() < 9)
        return;
    }
    auto len = static_cast<unsigned char>(temp.at(5));
    if (temp.length() < len)
      return;
    if (static_cast<unsigned char>(temp.at(len - 1)) != 0xff) {
      temp = temp.mid(1, temp.length());
      i = 0;
      continue;
    }
    QByteArray buff = temp.mid(0, len);
    handleFrame(buff);
    temp = temp.mid(len, temp.length());
    i = 0;
    continue;
  }
}

void MySerialPort::handleFrame(const QByteArray &data) {
  auto nodeID = static_cast<unsigned char>(data.at(6));
  auto devID = static_cast<unsigned char>(data.at(7));
  //  auto len = static_cast<unsigned char>(data.at(5));
  switch (nodeID) {
  case 0x01: {
    if (devID == 0x01) {
      // LED
      {
        int light1 = static_cast<unsigned char>(data.at(9));
        int light2 = static_cast<unsigned char>(data.at(11));
        int light3 = static_cast<unsigned char>(data.at(13));
        int light4 = static_cast<unsigned char>(data.at(15));
        MYPROFILE(ProfileType::UP,
                  QString("执行器 LED, 值 %1, 值 %2, 值 %3, 值 %4")
                      .arg(light1)
                      .arg(light2)
                      .arg(light3)
                      .arg(light4));

        SG_TCPSOCKET()->send_excute_data(
            ExcuteType::LED, (light1 << 8) | light2, (light3 << 8) | light4);
        led_state.led_on =
            (light1 == 0 && light2 == 0 && light3 == 0 && light4 == 0);
        led_state.l1 = light1;
        led_state.l2 = light2;
        led_state.l3 = light3;
        led_state.l4 = light4;
      }
    } else {
      MYPROFILE(
          ProfileType::WARNING,
          QString("执行器 节点 '%1' 未知设备 id '%2'").arg(nodeID).arg(devID));
    }
    break;
  }
  case 0x02: {
    switch (devID) {
    case 0x05: {
      // 0x02节点所有数据
      // 温湿度
      {
        double te, we;
        te = static_cast<double>(static_cast<unsigned char>(data.at(8)));
        te +=
            static_cast<double>(static_cast<unsigned char>(data.at(9))) * 0.01;
        we = static_cast<double>(static_cast<unsigned char>(data.at(10)));
        we +=
            static_cast<double>(static_cast<unsigned char>(data.at(11))) * 0.01;
        MYPROFILE(
            ProfileType::UP,
            QString("传感器 温湿度, 温度 %1℃, 湿度 %2%%").arg(te).arg(we));
        SG_TCPSOCKET()->send_sensor_data(SensorType::TEMP_WET, te, we);
        if (te >= 33.0 || we >= 70.0) {
          // 温度 >= 33 或 湿度 >= 70 开启风扇
          MYPROFILE(
              ProfileType::WARNING,
              QString(
                  "温湿度过高(te≥33℃/we≥70%)，开启风扇调节(如已开启请忽略)"));
          this->request_excute(ExcuteType::FAN, 1.0);
        }
        if (we < 40.0) {
          // 湿度 < 40 开启继电器1
          MYPROFILE(
              ProfileType::WARNING,
              QString("干燥警告(we&lt;30%)，开启喷淋调节(如已开启请忽略)"));
          this->request_excute(ExcuteType::RELAY, 1.0, 1.0);
          this->step_on(true);
        }
      }
      // CO2
      {
        int co2 = (static_cast<unsigned char>(data.at(12)) << 8) |
                  static_cast<unsigned char>(data.at(13));
        MYPROFILE(
            ProfileType::UP,
            QString("传感器 CO2, 浓度 %1ppm").arg(static_cast<double>(co2)));
        SG_TCPSOCKET()->send_sensor_data(SensorType::CO2, co2);
      }
      // 光照
      {
        double lux =
            static_cast<double>(static_cast<unsigned char>(data.at(14)));
        lux +=
            static_cast<double>(static_cast<unsigned char>(data.at(15))) * 0.01;
        MYPROFILE(ProfileType::UP, QString("传感器 光照, 强度 %1lm").arg(lux));
        SG_TCPSOCKET()->send_sensor_data(SensorType::LUX, lux);

        if (lux >= 100) {
          // 过亮 关闭高亮LED
          MYPROFILE(ProfileType::WARNING,
                    QString("光强警告(≥100lm)，关闭所有led"));
          SG_SERIALPORT()->request_excute(ExcuteType::LED, 0, 0);
          led_state.led_on = false;
        } else if (lux < 50) {
          // 弱光 设置为10
          MYPROFILE(ProfileType::WARNING,
                    QString("弱光警告(&lt;50lm)，打开所有led"));
          SG_SERIALPORT()->request_excute(ExcuteType::LED, 0x0f0f, 0x0f0f);
          led_state.led_on = true;
        }
        if (led_state.led_on) {
          if (lux >= 80) {
            // 调节亮度为6
            SG_SERIALPORT()->request_excute(ExcuteType::LED, 0x0505, 0x0505);
          }
        }
      }
      // 紫外
      {
        double uvs = static_cast<unsigned char>(data.at(16) << 8) |
                     static_cast<unsigned char>(data.at(17));
        MYPROFILE(ProfileType::UP, QString("传感器 紫外线, 强度 %1").arg(uvs));
        SG_TCPSOCKET()->send_sensor_data(SensorType::UVs, uvs);
      }
      break;
    }
    default:
      MYPROFILE(
          ProfileType::WARNING,
          QString("传感器 节点 '%1' 未知设备 id '%2'").arg(nodeID).arg(devID));
      break;
    }
    break;
  }
  case 0x03: {
    switch (devID) {
    case 0x05: {
      // 0x03所有数据
      // 烟雾
      {
        bool frag = static_cast<unsigned char>(data.at(8));
        MYPROFILE(ProfileType::UP, QString("传感器 烟雾 '%1'").arg(frag));
        SG_TCPSOCKET()->send_sensor_data(SensorType::FRAG, frag);
      }
      // 火光
      {
        bool fire = static_cast<unsigned char>(data.at(9));
        MYPROFILE(ProfileType::UP, QString("传感器 火光 '%1'").arg(fire));
        SG_TCPSOCKET()->send_sensor_data(SensorType::FIRE, fire);
      }
      break;
    }
    case 0x04:
    case 0x02:
    default:
      MYPROFILE(
          ProfileType::WARNING,
          QString("传感器 节点 '%1' 未知设备 id '%2'").arg(nodeID).arg(devID));
      break;
    }
    break;
  }
  case 0x07: {
    if (devID == 0x04) {
      // 所有数据 [风扇、电机位置、继电器1、继电器2]
      MYPROFILE(ProfileType::UP,
                QString("执行器 所有数据（风扇、电机位置、继电器1、继电器2）"));
    } else if (devID == 0x01) {
      // 风扇
      auto fan_on = static_cast<unsigned char>(data.at(8));
      MYPROFILE(ProfileType::UP,
                QString("执行器 风扇 %1").arg(fan_on ? "打开" : "关闭"));
      SG_TCPSOCKET()->send_excute_data(ExcuteType::FAN, fan_on ? 1.0 : -1.0);
    } else if (devID == 0x02) {
      // 步进电机
      auto st_dir = static_cast<unsigned char>(data.at(8));
      SG_TCPSOCKET()->send_excute_data(ExcuteType::STEP,
                                       step_state.is_on ? 1.0 : -1.0);
      if (st_dir != 0) {
        // 前进
        step_state.step++;
        if (step_state.step >= StepState::MAX_STEP) {
          step_state.step = StepState::MAX_STEP;
          step_state.is_front = false;
        }
      } else {
        step_state.step--;
        if (step_state.step <= 0) {
          step_state.step = 0;
          step_state.is_front = true;
        }
      }
    } else if (devID == 0x03) {
      // 继电器
      auto rel_id = static_cast<unsigned char>(data.at(8));
      auto rel_on = static_cast<unsigned char>(data.at(9));
      MYPROFILE(ProfileType::UP, QString("执行器 继电器 %1号 %2")
                                     .arg(rel_id)
                                     .arg(rel_on ? "打开" : "关闭"));
      SG_TCPSOCKET()->send_excute_data(
          ExcuteType::RELAY, rel_id == 1 ? 1.0 : -1.0, rel_on ? 1.0 : -1.0);
    } else {
      MYPROFILE(
          ProfileType::WARNING,
          QString("执行器 节点 '%1' 未知设备 id '%2'").arg(nodeID).arg(devID));
    }
    break;
  }
  default:
    MYPROFILE(ProfileType::WARNING,
              QString("下位机 未知节点 id '%1'").arg(nodeID));
    break;
  }
}
